﻿using Admin.Crypto.Model;
using Admin.Crypto.Runtime;
using Admin.Crypto.Session;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using SqlSugar;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Runtime;
using System.Text;

namespace Admin.Crypto
{
    /// <summary>
    /// start up
    /// </summary>
    public class Startup
    {
        /// <summary>
        /// start up
        /// </summary>
        /// <param name="configuration">配置接口</param>
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        /// <summary>
        /// 配置
        /// </summary>
        public IConfiguration Configuration { get; }
     
        /// <summary>
        /// 服务配置，注入组件所需要的依赖以及配置信息
        /// </summary>
        /// <param name="services">服务集合</param>
        public void ConfigureServices(IServiceCollection services)
        {
            var env = CommandUtils.EnvPort.Env;           
            services.AddOptions();
            services.AddHttpContextAccessor();
            services.AddSingleton(Configuration);
            services.AddOptions<JWTSettingsOptions>()
                               .BindConfiguration("JWTSettings")
                               .ValidateDataAnnotations();

            var jwtSettings = Configuration.GetSection("JWTSettings").Get<JWTSettingsOptions>();

            var defaultConnectionString = "server=127.0.0.1;database=study;port=3306;uid=root;pwd=123456;charset=utf8mb4;Convert Zero Datetime=True;SslMode=None;Allow User Variables=True;Connect Timeout=90;AllowLoadLocalInfile=true;";
            var sqlSugar = new SqlSugarScope(new ConnectionConfig
            {
                ConnectionString = defaultConnectionString,
                DbType = DbType.MySql,
                IsAutoCloseConnection = true,
                SlaveConnectionConfigs = new List<SlaveConnectionConfig> {
                                            new SlaveConnectionConfig {
                                                ConnectionString = defaultConnectionString,
                                                HitRate = 100
                                            }
                                        }
            });

            sqlSugar.DbMaintenance.CreateDatabase();
            sqlSugar.CodeFirst.InitTables(typeof(CustomerContact));
            services.AddSingleton<ISqlSugarClient>(_ => sqlSugar);
            services.AddTransient<ICustomerContactRepository, CustomerContactRepository>();
            services.AddTransient<ICustomerContactAppService, CustomerContactAppService>();
            services.AddTransient<IPrincipalAccessor, AspNetCorePrincipalAccessor>();
            services.AddTransient<IUserSession, UserSession>();
            services.AddEndpointsApiExplorer();
            services.AddSwaggerGen(options =>
            {
                options.CustomSchemaIds(x => x.FullName);
                options.ResolveConflictingActions(x => x.FirstOrDefault());
                var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
                var files = Directory.GetFiles(basePath, "*.xml");
                foreach (var item in files)
                {
                    options.IncludeXmlComments(item, true);
                }

                //options.SwaggerDoc("v1", new OpenApiInfo { Title = "Admin.Crypto.WebApi", Version = "v1" });
                //options.OperationFilter<AssignOAuth2SecurityRequirements>();
                //options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                //{                    
                //    Type = SecuritySchemeType.ApiKey,
                //    BearerFormat = "JWT",
                //    Scheme = JwtBearerDefaults.AuthenticationScheme,
                //    Name = "Authorization",
                //    In = ParameterLocation.Header,
                //    Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" },
                //    Flows = new OpenApiOAuthFlows
                //    {                        
                //        ClientCredentials = new OpenApiOAuthFlow
                //        {
                //            TokenUrl = new Uri("/oauth2/login", UriKind.Relative),
                //        }
                //    }
                //});
            });

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })            
            .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = jwtSettings.ValidateIssuer ?? true,
                    ValidateAudience = jwtSettings.ValidateAudience ?? true,
                    ValidateLifetime = jwtSettings.ValidateLifetime ?? true,
                    ClockSkew = jwtSettings.ClockSkew.HasValue ? TimeSpan.FromSeconds(jwtSettings.ClockSkew.Value) : TimeSpan.Zero,
                    ValidateIssuerSigningKey = jwtSettings.ValidateIssuerSigningKey ?? true,
                    ValidIssuer = jwtSettings.ValidIssuer,
                    ValidAudience = jwtSettings.ValidAudience,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.IssuerSigningKey))
                };
            });

            services.AddAuthorization().AddControllers();
        }
     
        /// <summary>
        /// 配置http管道
        /// </summary>
        /// <param name="app">应用构建器</param>
        /// <param name="env">host环境变量</param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {          
            if (env.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }
       
            app.UseAuthentication();
            app.UseRouting();            
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();              
            });   
        }     
        
    }

    public class AssignOAuth2SecurityRequirements : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
                                || context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
            if (hasAuthorize)
            {
                operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
                operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" });

                operation.Security = new List<OpenApiSecurityRequirement>
                {
                    new OpenApiSecurityRequirement
                    {
                        [
                            new OpenApiSecurityScheme {Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "oauth2"}
                            }
                        ] = new[] {"api1"}
                    }
                };
            }
        }
    }
}
